#ifndef diagram_H
#define diagram_H

#include <QGraphicsScene>
#include <QMutableHashIterator>
#include <QtGui>
#include "box.h"
#include "link.h"
#include "diagramTextItem.h"
#include "box_clipboard.h"
#include <QClipboard>
#include "frame.h"

class QGraphicsSceneMouseEvent;
class box;
class link;
class diagramTextItem;
class frame;


/*! \class diagram
    \brief Класс диаграммы
*/
class diagram : public QGraphicsScene{
	Q_OBJECT

public:
    enum Mode { 
				MoveItem = 0,  
				InsertLink = 1, 
				InsertItem = 2,
				EditLink = 3, 
				DrawLink = 4,  
				InsertText = 5, 
				MoveCopyItem = 6 };	//!< Режимы работы

	/*! Конструктор диаграммы "по умолчанию".
	*/
	diagram();

	/*! Конструктор с параметрами.
        \param _id идентификатор диаграммы
		\param _name имя диаграммы
	*/
	diagram(int _id, QString _name = QString());
	~diagram();

    int id;								//!< Индентификатор диаграммы
    int max_id;							//!< Максимальный ижентификатор элементов в данный момент
    Mode myMode;						//!< режим работы в данный момент времени
	Mode prevMode;						//!< Режим работы в предыдущий момент

    QString name;						//!< Имя диаграммы
    QHash<int,diagram*> children;       //!< Список дочерних диаграмм
    diagram* parent;					//!< Ссылка на родительскую диаграмму

    QHash<int,link*> links;				//!< Контейнер дуг
    QHash<int,box*> boxes;				//!< Контейнер блоков

	frame *mFrame;						//!< Рамка диаграммы

	link::ArrowType sideType;			//!< Вспомогательный тип стрелки
	QGraphicsRectItem *sideHighlight;	//!< Вспомогательные элементы диаграммы - края рабочей области

	bool altpr;							//!< Признак удержания клавиши Alt

	/*!	Добавление нового блока на диаграмму в заданной точке
		\param pos	Точка добавления блока
		\return		Идентификатор блока
	*/
    int  addBox(QPointF);						
	
	/*! Добавление блока на диаграмму в заданной точке
		\param pos	Точка добавления блока
		\param b	Блок
		\return		Идентификатор блока
	*/
    int  addBox(QPointF, box*);

	/*! Удаление блока из диаграммы
		\param b	Блок
	*/
    void removeBox(box* b);


    /*! Декомпозиция заданного блока
		\param b	Ссылка на декомпозируемый блок
		\return		Идентификатор дочерней диаграммы
    */
    int decomposeBox(box* b);
    
	/*! Получение указателя на дочернюю диаграмму по её идентификатору
		\param id	Идентификатор дочерней диаграммы
		\return		Указатель на дочернюю диаграмму
    */
	diagram *getChild(int id);

    /*! Добавление дуги на диаграмму
		\param lnk	Добавляемая дуга
		\return		Идентификатор дуги
    */
    int  addLink(link *lnk );
    
	/*! Удаление дуги из диаграммы
		\param lnk	Дуга
	*/
	void removeLink(link *lnk);
	
	/*! Удаление выделеных элементов из диаграммы
	*/
    void removeSelected();

    /*! Прикрепление дуги к блоку с заданым типом конечного сегмента
		\param lnk	Присоединяемая дуга
		\param b	Блок-приемник
		\param type     Тип дуги
		\param s        Сегмент, входящий в этот блок
    */
    void attachLink(link *lnk, box *b, link::ArrowType type, segment* s);
    
	/*! Отсоеднинение дуги от блока
		\param lnk	Отсоединяемая дуга
		\param b	Блок, от которого отсоединяют
    */
    void detachLink(link *lnk, box *b);

	/*! Перенос стрелки блока на его дочернюю диаграмму
		\param b	Блок, на дочернюю диаграмму которого необходим перенос
    */
    void transitLinks(box *b);          

	/*! Копирование выделенных блоков
	*/
    void copyBox();	
	
	/*! Вставка скопированных/вырезанных боксов
		\param here	Показывает, ну то же место, или со сдвигом будут размещаться объекты
    */
    void pasteBox(bool here);
    
	/*! Вырезание выделенных блоков
	*/
	void cutBox();

	/*! Рисование рамки
	*/
    void drawFrame();
	
	/*! Уничтожение дочерних диаграмм
	*/
	void killChildren();
	
	/*! Получение списка всех потомков диаграммы
		\return Список потомков
	*/
	QList<diagram *> getFamily();

	/*! Получение имени ноды текущей диаграммы
		\return Имя ноды
	*/
	QString node(){if (id<0) return QString("A-0"); else return QString("A%1").arg(id);};

protected:	
	void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);		//!< Переопределение стандартного обработчика события нажатие кнопок мыши
	void keyReleaseEvent ( QKeyEvent * keyEvent );					//!< Переопределение стандартного обработчика события клавиша отпущена
	void keyPressEvent ( QKeyEvent * keyEvent );					//!< Переопределение стандартного обработчика события клавиша нажата
	void mouseReleaseEvent( QGraphicsSceneMouseEvent * mouseEvent );//!< Переопределение стандартного обработчика события отпускания мыши
	void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent);		//!< Переопределение стандартного обработчика события перемещение мыши

private:
    link	*temp;      //!< Стрелка, редактирование или создние которой происходит в данный момент
    segment *current;   //!< Конечный сегмент стрелки temp
	int		curNum;		//!< Текущий номер блока на диаграмме

signals:
	void boxInserted();					//!< Сигнал "Блок размещен"
	void linkInserted();				//!< Сигнал "Дуга размещена"
	void childBorn(diagram *child);		//!< Сигнал	"Потомок создан"
    void childDied(int id);				//!< Сигнал "Потомок удален"
	void someChanges();				//!< Сигнал "Потомок удален"	
	
public slots:
	/*! Установка текущего режима работы со сценой
		\param mode Режим
	*/
    void setMode(Mode mode);
};

#endif 